﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Web;
using Eneta.Portal.Common.Dto;
using Eneta.Portal.Common.Helpers;
using Microsoft.SharePoint;

namespace Eneta.Portal.Common.Repository
{
    /// <summary>
    /// Class for forums operations.
    /// </summary>
    public class ForumRepository : BaseRepository 
    {
        public ForumRepository(SPWeb web) : base(web)
        {            
        }
        
        public IList<ForumDto> GetForumsForFrontPage()
        {
            IList<ForumDto> result = null;
            var sec = new SPSecurity.CodeToRunElevated(delegate
               { 
                   using(var site = new SPSite(SiteId))
                   using(var web = site.OpenWeb("/foorum/"))
                   {
                       result = GetForumsForFrontPage(web);
                   }
               });
            SPSecurity.RunWithElevatedPrivileges(sec);

            return result;
        }

        private IList<ForumDto> GetForumsForFrontPage(SPWeb web)
        {
            IList<ForumDto> forums = new List<ForumDto>(3);
            var lastPost = int.MaxValue;
            var control = 0;
            while (lastPost > 1 || forums.Count < 3)
            {
                control++;
                if (control > 10)
                    break;

                if (forums.Count == 3)
                    return forums;

                var queryString = "<Where><Leq><FieldRef Name='ID' /><Value Type='int'>{0}</Value></Leq></Where>";
                queryString += "<OrderBy><FieldRef Name='ID' Ascending='False' /></OrderBy>";
                queryString = string.Format(queryString, lastPost);

                var postList = web.Lists["spforums_posts"];
                var topicList = web.Lists["spforums_topics"];
                var forumList = web.Lists["spforums_forums"];

                var query = new SPQuery {Query = queryString, RowLimit = 25};
                query.ViewFields = "<FieldRef Name='TopicID' />";
                var postItems = postList.GetItems(query);

                for (var postCounter = 0; postCounter < postItems.Count; postCounter++)
                {
                    if (forums.Count == 3)
                        return forums;

                    var postItem = postItems[postCounter];
                    lastPost = postItem.ID;

                    if (postItem["TopicID"] == null)
                        continue;

                    queryString = "<Where><Eq><FieldRef Name='ID' /><Value Type='int'>{0}</Value></Eq></Where>";
                    queryString = string.Format(queryString, postItem["TopicID"]);

                    query = new SPQuery {Query = queryString, RowLimit = 1};
                    query.ViewFields = "<FieldRef Name='ForumID' />";

                    var topicItems = topicList.GetItems(query);
                    if (topicItems.Count == 0)
                        continue;

                    var topicItem = topicItems[0];
                    if (topicItem["ForumID"] == null)
                        continue;

                    queryString = "<Where><Eq><FieldRef Name='ID' /><Value Type='int'>{0}</Value></Eq></Where>";
                    queryString = string.Format(queryString, topicItem["ForumID"]);

                    query = new SPQuery {Query = queryString, RowLimit = 1};
                    var forumItems = forumList.GetItems(query);
                    if (forumItems.Count == 0)
                        continue;

                    var forumItem = forumItems[0];

                    var forumQuery = from f in forums
                                     where f.Id == forumItem.ID
                                     select f;

                    if (forumQuery.Count() > 0)
                        continue;

                    forums.Add(CreateForum(forumItem));
                }
            }
            //var queryString = "<OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy>";
            //var list = web.Lists["spforums_topics"];
            //var query = new SPQuery {Query = queryString};
            //query.ViewFields = "<FieldRef Name='ForumId' />";
            //var items = list.GetItems(query);

            //if (items.Count == 0)
            //    return forums;



            //var topics = CreateForumTopics(items);
            //forums = 
            //            (from t in topics
            //           select GetForumById(web, t.ForumId)).Distinct().Take(3).ToList();
            for (var i = 0; i < 3 - forums.Count; i++)
                forums.Add(null);
            return forums;
        }

        /// <summary>
        /// Gets the forum by id.
        /// </summary>
        /// <param name="forumId">The forum id.</param>
        /// <returns></returns>
        public ForumDto GetForumById(int forumId)
        {
            ForumDto dto = null;

            var sec = new SPSecurity.CodeToRunElevated(delegate
                       {
                           using (var site = new SPSite(SiteId))
                           using (var web = site.OpenWeb("/foorum/"))
                           {
                               dto = GetForumById(web, forumId);
                           }
                       });
            SPSecurity.RunWithElevatedPrivileges(sec);

            return dto;
        }

        private ForumDto GetForumById(SPWeb web, int forumId)
        {
            var item = web.Lists["spforums_forums"].GetItemById(forumId);
            return CreateForum(item);
        }

        /// <summary>
        /// Gets the forum category by id.
        /// </summary>
        /// <param name="categoryId">The category id.</param>
        public ForumCategoryDto GetForumCategoryById(int categoryId)
        {
            ForumCategoryDto dto = null;

            var sec = new SPSecurity.CodeToRunElevated(delegate
                        {
                            using (var site = new SPSite(SiteId))
                            using (var web = site.OpenWeb("/foorum/"))
                            {
                                dto = GetForumCategoryById(web, categoryId);
                            }
                        });
            SPSecurity.RunWithElevatedPrivileges(sec);

            return dto;            
        }

        private ForumCategoryDto GetForumCategoryById(SPWeb web, int categoryId)
        {
            var item = web.Lists["spforums_category"].GetItemById(categoryId);
            return CreateForumCategory(item, false);
        }

        /// <summary>
        /// Gets the forum category RSS as string.
        /// </summary>
        /// <param name="categoryId">The category id.</param>
        public string GetForumCategoryRss(int categoryId)
        {
            var rss = string.Empty;

            var sec = new SPSecurity.CodeToRunElevated(delegate
                  {
                      using(var site = new SPSite(SiteId))
                      using(var web = site.OpenWeb("/foorum/"))
                      {
                          rss = GetForumCategoryRss(web, categoryId);
                      }
                  }                                         
                );
            SPSecurity.RunWithElevatedPrivileges(sec);

            return rss;
        }

        /// <summary>
        /// Gets the forum category RSS.
        /// </summary>
        /// <param name="web">The web where forum lists are located.</param>
        /// <param name="categoryId">The category id.</param>
        public string GetForumCategoryRss(SPWeb web, int categoryId)
        {
            var category = GetForumCategoryById(categoryId);
            var forums = GetForumsByCategoryId(categoryId);
            var topics = new List<ForumTopicDto>();

            foreach(var forum in forums)
            {
                var forumTopics = GetTopicsByForumId(web, forum.Id, 100);
                topics.AddRange(forumTopics);
            }

            topics = topics.Take(100).ToList();

            var posts = new List<ForumPostDto>();
            foreach(var topic in topics)
            {
                topic.Starter.Topic = topic;
                posts.Add(topic.Starter);
            }
            var title = "Eneta foorum: " + category.Title;
            var url = "/foorum/Lehed/default.aspx?control=ViewForums&amp;category=" + categoryId;
            var rss = CreateRss(title, url, posts, false);
            rss = RegExHelper.CleanForumBody(rss);
            return rss;
        }

        /// <summary>
        /// Gets the forum category comments RSS as string.
        /// </summary>
        /// <param name="categoryId">The category id.</param>
        public string GetForumCategoryCommentsRss(int categoryId)
        {
            var rss = string.Empty;

            var sec = new SPSecurity.CodeToRunElevated(delegate
                        {
                            using (var site = new SPSite(SiteId))
                            using (var web = site.OpenWeb("/foorum/"))
                            {
                                rss = GetForumCategoryCommentsRss(web, categoryId);
                            }
                        });
            SPSecurity.RunWithElevatedPrivileges(sec);

            return rss;
        }

        private string GetForumCategoryCommentsRss(SPWeb web, int categoryId)
        {
            var category = GetForumCategoryById(categoryId);
            var forums = GetForumsByCategoryId(categoryId);
            var topics = new List<ForumTopicDto>();

            foreach (var forum in forums)
            {
                var forumTopics = GetTopicsByForumId(web, forum.Id, 25);
                topics.AddRange(forumTopics);
            }

            topics = topics.Take(100).ToList();

            var posts = new List<ForumPostDto>();
            foreach (var topic in topics)
            {
                var replies = GetForumPostsByTopicId(web, topic.Id, 0);
                
                var starterId = topic.Starter.Id;
                var starter = replies.FirstOrDefault(p => p.Id == starterId);
                if (starter != null)
                    replies.Remove(starter);

                foreach (var post in replies)
                    post.Topic = topic;
                posts.AddRange(replies);
            }
            posts = posts.OrderByDescending(p => p.Created).Take(100).ToList();

            var title = "Eneta foorum: " + category.Title + ": Kommentaarid";
            var url = "/foorum/Lehed/default.aspx?control=ViewForums&amp;category=" + categoryId;

            var rss = CreateRss(title, url, posts, true);
            rss = RegExHelper.CleanForumBody(rss);
            return rss;
        }

        /// <summary>
        /// Gets the forum topic by id.
        /// </summary>
        /// <param name="topicId">The topic id.</param>
        public ForumTopicDto GetForumTopicById(int topicId)
        {
            ForumTopicDto topic = null;
            var sec = new SPSecurity.CodeToRunElevated(delegate
                            {
                                using(var site = new SPSite(SiteId))
                                using(var web = site.OpenWeb("/foorum/"))
                                {
                                    topic = GetForumTopicById(web, topicId);
                                }
                            }
                        );
            SPSecurity.RunWithElevatedPrivileges(sec);
            return topic;
        }

        private ForumTopicDto GetForumTopicById(SPWeb web, int topicId)
        {
            var list = web.Lists["spforums_topics"];

            var queryString = "<Where><Eq><FieldRef Name='ID' /><Value Type='int'>{0}</Value></Eq></Where>";
            queryString = string.Format(queryString, topicId);

            var topicItems = ExecuteQuery(list, queryString);
            if (topicItems == null)
                return null;
            if (topicItems.Count == 0)
                return null;

            var topicItem = topicItems[0];
            return CreateForumTopic(topicItem);
        }

        /// <summary>
        /// Gets the list of forum categories.
        /// </summary>
        public IList<ForumCategoryDto> GetForumCategories()
        {
            IList<ForumCategoryDto> results = new List<ForumCategoryDto>();

            var sec = new SPSecurity.CodeToRunElevated(delegate
                          {
                              using(var site = new SPSite(SiteId))
                              using(var web = site.OpenWeb("/foorum/"))
                              {
                                  results = GetForumCategories(web);
                              }
                          });
            SPSecurity.RunWithElevatedPrivileges(sec);

            return results;
        }

        private IList<ForumCategoryDto> GetForumCategories(SPWeb web)
        {
            var categories = new List<ForumCategoryDto>();

            var list = web.Lists["spforums_category"];
            var items = list.Items;

            if (items == null)
                return categories;
            if (items.Count == 0)
                return categories;

            foreach(SPListItem item in items)
            {
                var dto = CreateForumCategory(item, true);
                categories.Add(dto);
            }

            return categories;
        }

        /// <summary>
        /// Gets the list of forums.
        /// </summary>
        public IList<ForumDto> GetForums()
        {
            IList<ForumDto> results = new List<ForumDto>();

            var sec = new SPSecurity.CodeToRunElevated(delegate
            {
                using (var site = new SPSite(SiteId))
                using (var web = site.OpenWeb("/foorum/"))
                {
                    results = GetForums(web);
                }
            });
            SPSecurity.RunWithElevatedPrivileges(sec);

            return results;                        
        }

        private IList<ForumDto> GetForums(SPWeb web)
        {
            var forums = new List<ForumDto>();

            var list = web.Lists["spforums_forums"];
            var items = list.Items;

            if (items == null)
                return forums;
            if (items.Count == 0)
                return forums;

            foreach (SPListItem item in items)
            {
                var dto = CreateForum(item);
                forums.Add(dto);
            }

            return forums;
             
        }

        /// <summary>
        /// Gets the list of forums by category id.
        /// </summary>
        /// <param name="categoryId">The category id.</param>
        public IList<ForumDto> GetForumsByCategoryId(int categoryId)
        {
            IList<ForumDto> results = new List<ForumDto>();

            var sec = new SPSecurity.CodeToRunElevated(delegate
            {
                using (var site = new SPSite(SiteId))
                using (var web = site.OpenWeb("/foorum/"))
                {
                    results = GetForumsByCategoryId(web, categoryId);
                }
            });
            SPSecurity.RunWithElevatedPrivileges(sec);

            return results;            
        }

        /// <summary>
        /// Gets the list of topics by forum id.
        /// </summary>
        /// <param name="forumId">The forum id.</param>
        public IList<ForumTopicDto> GetTopicsByForumId(int forumId)
        {
            return GetTopicsByForumId(forumId, 0);
        }

        /// <summary>
        /// Gets the list of topics by forum id.
        /// </summary>
        /// <param name="forumId">The forum id.</param>
        /// <param name="limit">The number of topics to retrieve. 0 means retrieve all.</param>
        /// <returns></returns>
        public IList<ForumTopicDto> GetTopicsByForumId(int forumId, int limit)
        {
            IList<ForumTopicDto> topics = new List<ForumTopicDto>();
            var sec = new SPSecurity.CodeToRunElevated(delegate
                  {
                      using(var site =new SPSite(SiteId))
                      using(var web = site.OpenWeb("/foorum/"))
                      {
                          topics = GetTopicsByForumId(web, forumId, limit);
                      }
                  }                                         
                );
            SPSecurity.RunWithElevatedPrivileges(sec);
            return topics;
        }        

        private IList<ForumTopicDto> GetTopicsByForumId(SPWeb web, int forumId, int limit)
        {
            IList<ForumTopicDto> topics = new List<ForumTopicDto>();

            var list = web.Lists["spforums_topics"];
            var items = QueryItemsByFieldValue(list, "ForumID", forumId.ToString(),"Created", false,limit);
            if (items == null)
                return topics;
            if (items.Count == 0)
                return topics;

            foreach(SPListItem item in items)
            {
                var dto = CreateForumTopic(item);
                if (dto != null)
                    topics.Add(dto);
            }

            return topics;
        }

        /// <summary>
        /// Gets the forum post by id.
        /// </summary>
        /// <param name="id">The id of forum post.</param>
        public ForumPostDto GetForumPostById(int id)
        {
            ForumPostDto result = null;

            var sec = new SPSecurity.CodeToRunElevated(delegate
                            {
                                using (var site = new SPSite(SiteId))
                                using (var web = site.OpenWeb("/foorum/"))
                                {
                                    result = GetForumPostById(web, id);
                                }
                            }
                        );
            SPSecurity.RunWithElevatedPrivileges(sec);
            return result;
        }

        private ForumPostDto GetForumPostById(SPWeb web, int id)
        {
            var list = web.Lists["spforums_posts"];
            var items = QueryItemsByFieldValue(list, "ID", id.ToString(), "Created", true, 1);
            if (items == null || items.Count == 0)
                return null;

            return CreateForumPost(items[0]);
        }

        public IList<ForumPostDto> GetForumPostsByTopicId(int topicId)
        {
            return GetForumPostsByTopicId(topicId, 0);
        }


        /// <summary>
        /// Gets the list of forum posts by topic id.
        /// </summary>
        /// <param name="topicId">The topic id.</param>
        public IList<ForumPostDto> GetForumPostsByTopicId(int topicId, int limit)
        {
            IList<ForumPostDto> results = new List<ForumPostDto>();

            var sec = new SPSecurity.CodeToRunElevated(delegate
                            {
                                using(var site = new SPSite(SiteId))
                                using(var web = site.OpenWeb("/foorum/"))
                                {
                                    results = GetForumPostsByTopicId(web, topicId, limit);
                                }
                            }                                   
                        );
            SPSecurity.RunWithElevatedPrivileges(sec);
            return results;
        }

        private IList<ForumPostDto> GetForumPostsByTopicId(SPWeb web, int topicId, int limit)
        {
            IList<ForumPostDto> results = new List<ForumPostDto>();

            var list = web.Lists["spforums_posts"];
            var items = QueryItemsByFieldValue(list, "TopicID", topicId.ToString(), "Created", true, limit);

            if (items == null)
                return results;
            if (items.Count == 0)
                return results;

            foreach(SPListItem item in items)
            {
                var dto = CreateForumPost(item);
                if (dto != null)
                    results.Add(dto);
            }

            return results;
        }

        /// <summary>
        /// Increases the topic view count by one.
        /// </summary>
        /// <param name="topicId">The topic id.</param>
        public void IncreaseTopicViewCount(int topicId)
        {
            var sec = new SPSecurity.CodeToRunElevated(delegate
                            { 
                                using(var site = new SPSite(SiteId))
                                using(var web = site.OpenWeb("/foorum/"))
                                {
                                    site.AllowUnsafeUpdates = true;
                                    web.AllowUnsafeUpdates = true;
                                    IncreaseTopicViewCount(web, topicId);
                                }
                            }
                        );
            SPSecurity.RunWithElevatedPrivileges(sec);
        }

        private void IncreaseTopicViewCount(SPWeb web, int topicId)
        {
            var list = web.Lists["spforums_topics"];
            var item = QueryItemByFieldValue(list, "ID", topicId.ToString());
            if (item == null)
                return;

            var count = 0;
            if (item["Views"] != null)
                int.TryParse(item["Views"].ToString(), out count);
            count++;

            item["Views"] = count;
            item.Update();
        }

        /// <summary>
        /// Saves the forum post.
        /// </summary>
        /// <param name="post">The post to save.</param>
        public void SaveForumPost(ForumPostDto post)
        {
            var sec = new SPSecurity.CodeToRunElevated(delegate
                  { 
                      using(var site = new SPSite(SiteId))
                      using(var web = site.OpenWeb("/foorum/"))
                      {
                          SaveForumPost(web, post);
                      }
                  }                                         
                );
            SPSecurity.RunWithElevatedPrivileges(sec);
        }

        private void SaveForumPost(SPWeb web, ForumPostDto post)
        {
            var list = web.Lists["spforums_posts"];
            SPListItem item;

            if (post.Id == 0)
            {
                item = list.Items.Add();
                item["Author"] = web.SiteUsers[post.AuthorUserName];
            }
            else
                item = list.GetItemById(post.Id);

            item["Title"] = post.Title;
            item["Body"] = post.Body;            
            item["TopicID"] = post.TopicId;
            item["ForumID"] = post.ForumId;
            if (post.Id > 0)
            {
                item["Editor"] = web.SiteUsers[post.ModifiedByUserName];
                item["EditorExplanation"] = post.EditorExplanation;
            }
            item.Update();
        }

        /// <summary>
        /// Gets the forum common RSS as string.
        /// </summary>
        public string GetCommonRss()
        {
            var rss = string.Empty;

            var sec = new SPSecurity.CodeToRunElevated(delegate
                          { 
                              using(var site = new SPSite(SiteId))
                              using(var web = site.OpenWeb("/foorum/"))
                              {
                                  rss = GetCommonRss(web);
                              }
                          }
                        );
            SPSecurity.RunWithElevatedPrivileges(sec);

            return rss;
        }

        private string GetCommonRss(SPWeb web)
        {
            var list = web.Lists["spforums_topics"];
            
            var query = new SPQuery();
            query.Query = "<OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy>";
            query.RowLimit = 25;

            var items = list.GetItems(query);
            var topics = CreateForumTopics(items);
            var posts = new List<ForumPostDto>();

            foreach(var topic in topics)
            {
                var post = topic.Starter;
                if (post == null)
                    continue;

                post.Topic = topic;
                posts.Add(post);
            }

            var url = "http://www.eneta.ee/foorum/Lehed/default.aspx";
            var title = "Eneta foorum";

            var rss = CreateRss(title, url, posts, false);
            rss = RegExHelper.CleanForumBody(rss);
            return rss;
        }

        public string GetForumRss(int forumId)
        {
            var rss = string.Empty;

            var sec = new SPSecurity.CodeToRunElevated(delegate
                          {
                              using(var site  = new SPSite(SiteId)) 
                              using(var web = site.OpenWeb("/foorum/"))
                              {
                                  rss = GetForumRss(web, forumId);
                              }
                          }                                         
                        );
            SPSecurity.RunWithElevatedPrivileges(sec);

            return rss;
        }

        private string GetForumRss(SPWeb web, int forumId)
        {
            var list = web.Lists["spforums_topics"];
            var items = QueryItemsByFieldValue(list, "ForumID", forumId.ToString(), "Created", false, 50);
            var topics = CreateForumTopics(items);

            var posts = new List<ForumPostDto>();

            foreach(var topic in topics)
            {
                if (topic.Starter == null)
                    continue;

                topic.Starter.Topic = topic;
                posts.Add(topic.Starter);
            }

            var forum = GetForumById(web, forumId);
            var url = "http://www.eneta.ee/foorum/Lehed/default.aspx?control=ViewTopics&amp;forum=" + forumId;
            var title = forum.Category.Title + ": " + forum.Title;
            
            var rss = CreateRss(title, url, posts, false);
            rss = RegExHelper.CleanForumBody(rss);
            return rss;
        }

        /// <summary>
        /// Gets the forum comments RSS as string.
        /// </summary>
        public string GetCommentsRss()
        {
            var rss = string.Empty;

            var sec = new SPSecurity.CodeToRunElevated(delegate
                          {
                              using(var site = new SPSite(SiteId))
                              using(var web = site.OpenWeb("/foorum/"))
                              {
                                  rss = GetCommentsRss(web);
                              }
                          }                                         
                        );
            SPSecurity.RunWithElevatedPrivileges(sec);

            return rss;
        }

        private string GetCommentsRss(SPWeb web)
        {
            var list = web.Lists["spforums_posts"];
            var queryString = "<OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy>";

            var query = new SPQuery();
            query.Query = queryString;
            query.RowLimit = 100;

            HttpContext.Current.Trace.Write("GetCommentsRss(): Querying items");
            var items = list.GetItems(query);
            HttpContext.Current.Trace.Write("GetCommentsRss(): Query done, items: " + items.Count);
            var posts = CreateForumPosts(items,true);
            HttpContext.Current.Trace.Write("GetCommentsRss(): Forum posts created");
            var commentPosts = new List<ForumPostDto>();

            foreach(var post in posts)
            {
                if (post == null)
                    continue;
                if (post.Topic == null)
                    continue;

                if (post.Topic.Starter.Id == post.Id)
                    continue;
                commentPosts.Add(post);
            }
            var title = "Eneta foorumi kommentaarid";
            var url = "http://www.eneta.ee/foorum/";

            HttpContext.Current.Trace.Write("GetCommentsRss(): Filtered posts: " + commentPosts.Count);
            var rss = CreateRss(title, url, commentPosts, true);
            HttpContext.Current.Trace.Write("GetCommentsRss(): RSS created");
            rss = RegExHelper.CleanForumBody(rss);
            return rss;
        }

        public string GetTopicCommentsRss(int topicId)
        {
            var rss = string.Empty;

            var sec = new SPSecurity.CodeToRunElevated(delegate
                          {
                              using(var site = new SPSite(SiteId))
                              using(var web = site.OpenWeb("/foorum/"))
                              {
                                  rss = GetTopicCommentsRss(web, topicId);
                              }
                          }                                         
                        );
            SPSecurity.RunWithElevatedPrivileges(sec);

            return rss;
        }

        private string GetTopicCommentsRss(SPWeb web, int topicId)
        {
            var topic = GetForumTopicById(web, topicId);
            var posts = GetForumPostsByTopicId(web, topicId, 0);

            if (posts.Count > 0)
                posts.RemoveAt(0);

            var title = "Eneta foorum: " + topic.Title + " kommentaarid";
            var url = "http://www.eneta.ee/foorum/Lehed/default.aspx?control=ViewMessages&amp;topic=";
            url += topic.Id + "#comments";

            foreach (var post in posts)
                post.Topic = topic;

            //posts = posts.OrderBy(p => p.Created).ToList();

            var rss = CreateRss(title, url, posts, true);
            rss = RegExHelper.CleanForumBody(rss);
            return rss;
        }

        private string CreateRss(string title, string viewUrl, IEnumerable<ForumPostDto> posts, bool postsAreReplies)
        {
            var builder = new StringBuilder(GetRssHeader(title, viewUrl));

            if(posts == null)
            {
                builder.Append(GetRssFooter());
                return builder.ToString();
            }

            foreach(var post in posts)
            {
                if (post == null)
                    continue;
                if (post.Topic == null)
                    continue;
                builder.Append("<item>\r\n");
                
                builder.Append("<title>");
                if (postsAreReplies)
                    builder.Append("Re: ");
                if(!string.IsNullOrEmpty(post.Topic.Title))
                    builder.Append(post.Topic.Title.Replace("&","&amp;"));
                builder.Append("</title>\r\n");

                builder.Append("<link>");
                builder.Append("http://www.eneta.ee/foorum/Lehed/default.aspx?control=ViewMessages&amp;topic=" + post.Topic.Id);
                if (postsAreReplies)
                {
                    builder.Append("#");
                    builder.Append(post.Id);
                }
                builder.Append("</link>\r\n");

                if (!postsAreReplies)
                {
                    builder.Append("<comments>");
                    builder.Append("http://www.eneta.ee/foorum/Lehed/default.aspx?control=ViewMessages&amp;topic=");
                    builder.Append(post.Topic.Id);
                    builder.Append("#comments</comments>\r\n");
                }
                builder.Append("<pubDate>");
                builder.Append(post.Created.ToString("r"));
                builder.Append("</pubDate>\r\n");

                builder.Append("<dc:creator>");
                builder.Append(post.AuthorProfileName);
                builder.Append("</dc:creator>\r\n");

                //builder.Append("<category><![CDATA[");
                //
                //builder.Append("]]></category>");

                builder.Append("<guid isPermaLink=\"false\">");
                builder.Append("http://www.eneta.ee/foorum/Lehed/default.aspx?control=ViewMessages&amp;topic=" + post.Topic.Id);
                if(postsAreReplies)
                {
                    builder.Append("#");
                    builder.Append(post.Id);                    
                }
                builder.Append("</guid>\r\n");

                //builder.Append("<description>");
                //
                //builder.Append("</description>");

                builder.Append("<content:encoded><![CDATA[");
                //builder.Append(RegExHelper.DetectAndReplaceUrls(post.Body));
                builder.Append(post.Body);
                builder.Append("]]></content:encoded>\r\n");

                if (!postsAreReplies)
                {
                    builder.Append("<wfw:commentRss>");
                    builder.Append("http://www.eneta.ee/foorum/Lehed/default.aspx?control=ViewMessages&amp;topic=");
                    builder.Append(post.Topic.Id);
                    builder.Append("&amp;rss=1");
                    builder.Append("</wfw:commentRss>");
                
                    builder.Append("<slash:comments>");
                    builder.Append(post.Topic.PostCount);
                    builder.Append("</slash:comments>");
                }
                builder.Append("</item>");
            }
            builder.Append(GetRssFooter());
            return builder.ToString();
        }

        // Tõstetud baasklassi
        /*private string GetRssHeader(string title, string link)
        {
            var header = @"
                    <rss 
	                    xmlns:content=""http://purl.org/rss/1.0/modules/content/"" 
	                    xmlns:wfw=""http://wellformedweb.org/CommentAPI/"" 
	                    xmlns:dc=""http://purl.org/dc/elements/1.1/"" 
	                    xmlns:atom=""http://www.w3.org/2005/Atom"" 
	                    xmlns:sy=""http://purl.org/rss/1.0/modules/syndication/"" 
	                    xmlns:slash=""http://purl.org/rss/1.0/modules/slash/"" 
	                    version=""2.0"">
	                    <channel>
		                    <title>{0}</title>
		                    <link>{1}</link>
		                    <description></description>
		                    <lastBuildDate>{2}</lastBuildDate>
		                    <generator>Eneta portaal</generator>
		                    <language>et</language>
		                    <sy:updatePeriod>hourly</sy:updatePeriod>
		                    <sy:updateFrequency>1</sy:updateFrequency>
                ";
                            //<atom10:link 
                            //    xmlns:atom10=""http://www.w3.org/2005/Atom"" 
                            //    rel=""self"" 
                            //    href=""http://feeds.feedburner.com/wekeroad/EeKc"" 
                            //    type=""application/rss+xml"" />
            header = string.Format(header, title, link, DateTime.Now.ToString("r"));

            return header;
        }*/

        //private string GetRssFooter()
        //{
        //    return "</channel></rss>";
        //}

        private IList<ForumDto> GetForumsByCategoryId(SPWeb web, int categoryId)
        {
            var forums = new List<ForumDto>();

            var list = web.Lists["spforums_forums"];
            var items = QueryItemsByFieldValue(list, "CategoryID", categoryId.ToString());

            if (items == null)
                return forums;
            if (items.Count == 0)
                return forums;

            foreach(SPListItem item in items)
            {
                var dto = CreateForum(item);
                forums.Add(dto);
            }

            return forums;
        }

        private ForumPostDto GetLastPostForForum(SPWeb web, int forumId)
        {
            var queryString = "<Where><Eq><FieldRef Name='ForumID'/><Value Type='Number'>{0}</Value></Eq></Where>";
            queryString += "<OrderBy><FieldRef Name='Created' Ascending='False' /></OrderBy>";
            queryString = string.Format(queryString, forumId);

            //var topicsList = web.Lists["spforums_topics"];
            var postsList = web.Lists["spforums_posts"];

            /*var query = new SPQuery();
            query.Query = queryString;
            query.RowLimit = 1;

            /*var items = topicsList.GetItems(query);
            DateTime topicModified = DateTime.MinValue;
            if(items != null)
                if(items.Count > 0)
                {
                    topicModified = (DateTime) items[0]["Modified"];
                }

            */
            var query = new SPQuery();
            query.Query = queryString;
            query.RowLimit = 1;

            var items = postsList.GetItems(query);
            if (items != null)
                if (items.Count > 0)
                {
                    return CreateForumPost(items[0]);
                }

            return null;
            //var topicsListId = web.Lists["spforums_topics"];
            //var postsListId = web.Lists["spforums_posts"];

            //var lists = "<Lists Hidden='True'><List ID='{0}' /><List ID='{1}' /></Lists>";
            //lists = string.Format(lists, topicsListId, postsListId);

            //var queryString = "<Where><Eq><FieldRef Name='ForumID'/><Value Type='Number'>{0}</Value></Eq></Where>";
            ////queryString += "<OrderBy><FieldRef Name='Modified' Ascending='False' /></OrderBy>";
            //queryString = string.Format(queryString, forumId);

            //var query = new SPSiteDataQuery
            //                {
            //                    Lists = lists,
            //                    Query = queryString,
            //                    RowLimit = 1,
            //                    ViewFields = "<FieldRef Name='Modified' Nullable='True' />",
            //                    Webs = "<Webs Scope='Recursive'/>"
            //                };

            //DataTable results;
            //using (var newsWeb = web.Site.OpenWeb("/uudised/"))
            //{
            //    results = newsWeb.GetSiteData(query);
            //}
            //if (results == null)
            //{
            //    Logger.LogInfo("GetLastPostDateForForum(): no result set was returned", GetType().ToString());
            //    return null;
            //}
            //if (results.Rows.Count == 0)
            //{
            //    Logger.LogInfo("GetLastPostDateForForum(): result set is empty", GetType().ToString());
            //    return null;
            //}
            //DateTime? lastPostDate = (DateTime) results.Rows[0]["Modified"];
            //return lastPostDate;
        }

        private int GetTopicCountForForum(SPWeb web, int forumId)
        {
            var topicsList = web.Lists["spforums_topics"];

            var queryString = "<Where><Eq><FieldRef Name='ForumID'/><Value Type='Number'>{0}</Value></Eq></Where>";
            queryString = string.Format(queryString, forumId);

            var query = new SPQuery
                            {
                                Query = queryString, 
                                ViewFields = "<FieldRef Name='ID' />"
                            };

            var result = topicsList.GetItems(query);
            if (result == null)
                return -1;
            return result.Count;          
        }

        private int GetPostCountForForum(SPWeb web, int forumId)
        {
            var postsList = web.Lists["spforums_posts"];

            var queryString = "<Where><Eq><FieldRef Name='ForumID'/><Value Type='Number'>{0}</Value></Eq></Where>";
            queryString = string.Format(queryString, forumId);

            var query = new SPQuery
                            {
                                Query = queryString, 
                                ViewFields = "<FieldRef Name='ID' />"
                            };

            var result = postsList.GetItems(query);
            if (result == null)
                return -1;
            return result.Count;
        }

        private int GetPostCountForTopic(SPWeb web, int topicId)
        {
            var postsList = web.Lists["spforums_posts"];

            var queryString = "<Where><Eq><FieldRef Name='TopicID'/><Value Type='Number'>{0}</Value></Eq></Where>";
            queryString = string.Format(queryString, topicId);

            var query = new SPQuery
            {
                Query = queryString,
                ViewFields = "<FieldRef Name='ID' />"
            };

            var result = postsList.GetItems(query);
            if (result == null)
                return -1;
            return result.Count;
        }

        private ForumCategoryDto CreateForumCategory(SPListItem item, bool loadForums)
        {
            var dto = new ForumCategoryDto
                          {
                              Id = item.ID,
                              Title = item.Title,
                              Modified = (DateTime) item["Modified"],
                              Created= (DateTime)item["Created"]
                          };

            if(item["FeedBurnerUrl"] != null)
            {
                var urlvalue = new SPFieldUrlValue(item["FeedBurnerUrl"].ToString());
                dto.FeedBurnerUrl = urlvalue.Url;
            }
            if(loadForums)
                dto.Forums = GetForumsByCategoryId(dto.Id);
            return dto;
        }

        private ForumDto CreateForum(SPListItem item)
        {
            var dto = new ForumDto
                        {
                            Id = item.ID,
                            Title = item.Title,
                            Modified = (DateTime)item["Modified"],
                            Created = (DateTime)item["Created"]
                        };
            if (item["Description"] != null)
                dto.Description = item["Description"].ToString();

            dto.PostCount = GetPostCountForForum(item.Web, dto.Id);
            dto.TopicCount = GetTopicCountForForum(item.Web, dto.Id);
            dto.LastPost = GetLastPostForForum(item.Web, dto.Id);

            if(item["FeedBurnerUrl"] != null)
            {
                var fbUrlValue = new SPFieldUrlValue(item["FeedBurnerUrl"].ToString());
                dto.FeedBurnerUrl = fbUrlValue.Url;
            }

            if(item["Moderators"] != null)
            {
                var moderatorValues = new SPFieldUserValueCollection(item.Web, item["Moderators"].ToString());
                var profileRepository = new UserProfileRepository(item.Web);

                foreach(var moderatorValue in moderatorValues)
                {
                    var moderator = moderatorValue.User.LoginName;
                    var profile = profileRepository.GetUserProfileByUserName(moderator);
                    dto.Moderators.Add(profile);
                }
            }
            var categoryItem = item.Web.Lists["spforums_category"].GetItemById(int.Parse(item["CategoryID"].ToString()));
            dto.Category = CreateForumCategory(categoryItem, false);
            return dto;
        }

        private IList<ForumPostDto> CreateForumPosts(SPListItemCollection items, bool includeTopics)
        {
            IList<ForumPostDto> posts = new List<ForumPostDto>();

            if (!includeTopics)
            {
                foreach (SPListItem item in items)
                {
                    posts.Add(CreateForumPost(item, includeTopics));
                }
                return posts;
            }
            
            var fieldCountInBatch = 15;
            var addedIds = new List<int>();
            var batchList = new List<int>();
            var topics = new List<ForumTopicDto>();

            for (var postCounter = 0; postCounter < items.Count; postCounter++ )
            {
                var postItem = items[postCounter];
                if (postItem["TopicID"] != null)
                {

                    var topicId = int.Parse(postItem["TopicID"].ToString());
                    if (topicId != 0)
                    {
                        if (!addedIds.Contains(topicId))
                        {
                            var post = CreateForumPost(postItem, false);
                            posts.Add(post);
                            batchList.Add(topicId);
                            addedIds.Add(topicId);
                        }
                    }
                }
                if (batchList.Count < fieldCountInBatch &&
                    postCounter < items.Count -1)
                    continue;

                var queryString = "";
                for (var i = 0; i < batchList.Count - 2; i++)
                {
                    queryString += "<Or>";
                }

                for (var i = 0; i < batchList.Count; i++)
                {
                    queryString += "<Eq><FieldRef Name='ID' /><Value Type='int'>" + batchList[i] + "</Value></Eq>";
                    if (i == 0)
                        continue;
                    queryString += "</Or>";
                }
                batchList.Clear();
                queryString = "<Where>" + queryString + "</Where>";

                Logger.LogWarning("RSS QUERY: " + queryString, "");

                var list = items[0].Web.Lists["spforums_topics"];
                var query = new SPQuery { Query = queryString };
                var topicItems = list.GetItems(query);

                foreach (SPListItem item in topicItems)
                    topics.Add(CreateForumTopic(item));
            }

            foreach (var post in posts)
            {
                if (post.TopicId == 0)
                    continue;

                var topic = (from t in topics
                             where t.Id == post.TopicId
                             select t).FirstOrDefault();
                post.Topic = topic;
            }

            return posts;
        }

        private ForumPostDto CreateForumPost(SPListItem item)
        {
            return CreateForumPost(item, false);
        }

        private ForumPostDto CreateForumPost(SPListItem item, bool includeTopics)
        {
            var dto = new ForumPostDto
                          {
                              Id = item.ID,
                              Title = item.Title,
                              Created = (DateTime) item["Created"],
                              Modified = (DateTime) item["Modified"]
                          };
            if(item["Body"] != null)
            {
                dto.Body = item["Body"].ToString();
            }
            if (item["TopicID"] != null)
                dto.TopicId = int.Parse(item["TopicID"].ToString());

            if(includeTopics)
                if(item["TopicID"] != null)
                {
                    int i;
                    int.TryParse(item["TopicID"].ToString(), out i);
                    dto.TopicId = i;

                    dto.Topic = GetForumTopicById(item.Web,i);
                    if(dto.Topic == null)
                    {
                        Logger.LogWarning("Cannot find topic with id: " + i, "CreateForumPost");
                    }
                }
            if(item["Author"] != null)
            {
                var authorValue = new SPFieldUserValue(item.Web, item["Author"].ToString());
                var author = authorValue.User;

                if(author != null)
                {
                    dto.AuthorProfileName = author.Name;
                    dto.AuthorUserName = author.LoginName;

                    var profileRep = new UserProfileRepository(item.Web);
                    var profile = profileRep.GetUserProfileByUserName(author.LoginName);
                    if(profile != null)
                    {
                        dto.OwnerProfileId = profile.Id.ToString();
                    }
                }
            }
            if (item["Editor"] != null)
            {
                var editorValue = new SPFieldUserValue(item.Web, item["Editor"].ToString());
                var editor = editorValue.User;

                if (editor != null)
                {
                    dto.ModifiedBy = editor.Name;
                    dto.ModifiedByUserName = editor.LoginName;
                }
            }
            if(item["EditorExplanation"] != null)
            {
                dto.EditorExplanation = item["EditorExplanation"].ToString();
            }
            return dto;
        }

        private IList<ForumTopicDto> CreateForumTopics(SPListItemCollection items)
        {
            IList<ForumTopicDto> topics = new List<ForumTopicDto>();
            foreach (SPListItem item in items)
                topics.Add(CreateForumTopic(item));
            return topics;
        }

        private ForumTopicDto CreateForumTopic(SPListItem item)
        {
            var dto = new ForumTopicDto
                          {
                              Id = item.ID,
                              Title = item.Title,
                              Created = (DateTime) item["Created"],
                              Modified = (DateTime) item["Modified"]
                          };
            if(item["ForumID"] != null)
            {
                int forumId;
                if (int.TryParse(item["ForumID"].ToString(), out forumId))
                    dto.ForumId = forumId;
            }
            if (item["Views"] != null)
            {
                int views;
                if (int.TryParse(item["Views"].ToString(), out views))
                    dto.Views = views;
            }

            dto.PostCount = GetPostCountForTopic(item.Web, dto.Id);
            if (dto.PostCount > 0)
                dto.PostCount--;

            var postItems = QueryItemsByFieldValue(item.Web.Lists["spforums_posts"], "TopicID", dto.Id.ToString(),
                                                  "Created", false, 0);
            if(postItems != null)
                if(postItems.Count > 0)
                {
                    var post = CreateForumPost(postItems[0]);
                    if(post != null)
                    {
                        dto.LastPostAuthor = post.AuthorProfileName;
                        dto.LastPostDate = post.Created;
                        dto.LastPostAuthorId = post.OwnerProfileId;
                    }

                    post = CreateForumPost(postItems[postItems.Count - 1]);
                    dto.Starter = post;
                }

            if(item["Author"] != null)
            {
                var authorValue = new SPFieldUserValue(item.Web, item["Author"].ToString());
                var author = authorValue.User;

                if(author != null)
                {
                    dto.AuthorProfileName = author.Name;
                    dto.AuthorUserName = author.LoginName;

                    var profileRep = new UserProfileRepository(item.Web);
                    var profile = profileRep.GetUserProfileByUserName(author.LoginName);
                    if(profile != null)
                    {
                        dto.AuthorProfileId = profile.Id;
                    }
                }
            }
            return dto;
        }
    }
}
